from apscheduler.schedulers.background import BackgroundScheduler
from utils.myredis import myRedis
from utils.bdapi import bdapi
from utils.webSocket import wbs
from models.m import IDCardInfo, User, UserNotification, Notification
import asyncio
import json
from datetime import datetime, timedelta

# 2. 初始化APScheduler调度器（使用后台线程执行任务）
scheduler = BackgroundScheduler()

# 保存主事件循环
_main_loop = None


def set_main_loop(loop):
    """保存主事件循环"""
    global _main_loop  # pylint: disable=global-statement
    _main_loop = loop


async def process_idcard_async():
    """异步处理身份证识别并保存到数据库"""
    while myRedis.llen("id_card") > 0:
        # 每次从队列头部弹出一个数据
        item = myRedis.lpop("id_card")
        if not item:
            break

        try:
            # 解析 Redis 中的 JSON 数据
            data = json.loads(
                item.decode() if isinstance(item, bytes) else item
            )
            user_id = data['user_id']
            picurl = data['picurl']

            # 调用百度 API 识别
            result = bdapi.idcard(picurl)
            print("识别成功--------------------")
            print(result)

            if result['code'] == 200:
                # 获取用户
                user = await User.get_or_none(id=user_id)
                if not user:
                    print(f"用户 {user_id} 不存在")
                    continue

                # 检查该用户是否已经有身份证信息
                existing_idcard = await IDCardInfo.get_or_none(
                    user_id=user_id
                )
                if existing_idcard:
                    # 更新现有信息
                    existing_idcard.name = result.get('name')
                    existing_idcard.idcard_number = result.get('idcard')
                    existing_idcard.image_url = {"url": picurl}
                    await existing_idcard.save()
                    print(f"用户 {user_id} 的身份证信息已更新")
                else:
                    # 检查身份证号是否已被其他用户使用
                    idcard_exists = await IDCardInfo.get_or_none(
                        idcard_number=result.get('idcard')
                    )
                    if idcard_exists:
                        msg = f"身份证号 {result.get('idcard')} 已被使用"
                        print(msg)
                        continue

                    # 创建新的身份证信息
                    await IDCardInfo.create(
                        user_id=user_id,
                        name=result.get('name'),
                        idcard_number=result.get('idcard'),
                        image_url={"url": picurl}
                    )
                    print(f"✅ 用户 {user_id} 的身份证信息已保存")

                # 更新用户的实名认证状态
                user.is_real = 1
                await user.save()
                print(f"✅ 用户 {user_id} 实名认证状态已更新")

                # 🔔 保存通知到数据库
                title = "🎉 实名认证成功"
                content = f"恭喜！您的实名认证已通过，姓名：{result.get('name')}"
                
                # 保存到通知表
                await Notification.create(
                    user_id=user_id,
                    title=title,
                    content=content,
                    type="success",
                    status=1,
                    extra_data={"idcard_number": result.get('idcard')}
                )
                print(f"✅ 已保存通知到数据库")
                
                # 通过 WebSocket 发送实时通知
                notification_data = {
                    "type": "success",
                    "title": title,
                    "content": content,
                    "status": 1,
                    "timestamp": asyncio.get_event_loop().time()
                }
                try:
                    await wbs.send_to_client(
                        str(user_id),
                        json.dumps(notification_data)
                    )
                    print(
                        f"✅ 已向用户 {user_id} 发送 "
                        f"WebSocket 认证成功通知"
                    )
                except Exception as ws_error:  # noqa: E722
                    print(
                        f"⚠️  WebSocket 发送失败"
                        f"（用户可能未连接）: {str(ws_error)}"
                    )
                    # 保存消息到临时通知表（用户未连接时可以稍后获取）
                    await UserNotification.create(
                        user_id=user_id,
                        message=notification_data
                    )
            else:
                print(f"❌ 识别失败: {result}")
        except (KeyError, ValueError, AttributeError) as e:
            print(f"❌ 处理身份证出错: {str(e)}")
        except IOError as e:
            print(f"❌ IO错误: {str(e)}")


def print_current_time():
    """
    同步包装函数（APScheduler 需要同步函数）
    使用主事件循环执行异步任务
    """
    try:
        if _main_loop and not _main_loop.is_closed():
            # 在主事件循环中安全地运行协程
            future = asyncio.run_coroutine_threadsafe(
                process_idcard_async(), _main_loop
            )
            # 等待结果（超时30秒）
            future.result(timeout=30)
        else:
            # 备选方案：创建新的事件循环
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(process_idcard_async())
            loop.close()
    except TimeoutError:
        print("❌ 定时任务执行超时")
    except RuntimeError as e:
        print(f"❌ 事件循环错误: {str(e)}")


async def clean_old_notifications_async():
    """
    异步清理旧通知
    - 删除 90 天前的已读通知
    - 删除 180 天前的未读通知（保留更久，防止用户遗漏）
    """
    try:
        now = datetime.now()
        
        # 清理 90 天前的已读通知
        read_cutoff_date = now - timedelta(days=90)
        deleted_read = await Notification.filter(
            is_read=True,
            created_at__lt=read_cutoff_date
        ).delete()
        
        # 清理 180 天前的未读通知
        unread_cutoff_date = now - timedelta(days=180)
        deleted_unread = await Notification.filter(
            is_read=False,
            created_at__lt=unread_cutoff_date
        ).delete()
        
        total_deleted = deleted_read + deleted_unread
        
        if total_deleted > 0:
            print(
                f"✅ 定时清理完成: "
                f"删除 {deleted_read} 条已读通知（>90天）, "
                f"{deleted_unread} 条未读通知（>180天）"
            )
        else:
            print("✅ 定时清理完成: 无需清理的通知")
            
    except Exception as e:
        print(f"❌ 清理旧通知失败: {str(e)}")


def clean_old_notifications_wrapper():
    """
    同步包装函数 - 清理旧通知
    """
    try:
        if _main_loop and not _main_loop.is_closed():
            future = asyncio.run_coroutine_threadsafe(
                clean_old_notifications_async(), _main_loop
            )
            future.result(timeout=60)
        else:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(clean_old_notifications_async())
            loop.close()
    except TimeoutError:
        print("❌ 清理通知任务执行超时")
    except RuntimeError as e:
        print(f"❌ 清理通知事件循环错误: {str(e)}")


def add_jobs():
    # 任务1：每隔5秒执行一次（interval触发）- 处理身份证识别
    scheduler.add_job(
        func=print_current_time,
        trigger="interval",  # 间隔触发
        seconds=5,  # 间隔5秒
        id="time_printer",  # 任务唯一ID（用于后续操作，如删除）
        max_instances=1  # 防止并发执行
    )
    
    # 任务2：每天凌晨3点清理旧通知（cron触发）
    scheduler.add_job(
        func=clean_old_notifications_wrapper,
        trigger="cron",  # cron 表达式触发
        hour=3,  # 每天凌晨3点
        minute=0,  # 0分
        id="clean_notifications",
        max_instances=1,
        misfire_grace_time=3600  # 如果错过执行时间，1小时内仍可补执行
    )
    print("✅ 定时任务已添加: 1) 身份证识别(每5秒) 2) 清理旧通知(每天3:00)")
